﻿using api_identity.Data;
using api_identity.Data.Entities;
using api_identity.Options;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace api_identity
{
    public static partial class Extensions
    {
        private static JwtOptions _jwtOptions;

        /// <summary>
        /// 添加身份服务
        /// </summary>
        /// <param name="services"></param>
        /// <param name="accountConfig"></param>
        /// <returns></returns>
        public static IServiceCollection AddIdentity(this IServiceCollection services, Func<AccountOptions> accountConfig = null)
        {
            services.AddIdentity<UserEntity, RoleEntity>(options =>
            {
                var accountOptions = accountConfig?.Invoke() ?? new AccountOptions();

                options.Password.RequireDigit = accountOptions.PwdContainNum;
                options.Password.RequireLowercase = accountOptions.PwdContainLowerCase;
                options.Password.RequireNonAlphanumeric = accountOptions.PwdContainNonAlphanumeric;
                options.Password.RequireUppercase = accountOptions.PwdContainUpperCase;
                options.Password.RequiredLength = accountOptions.PwdMinLength;

                options.Lockout.AllowedForNewUsers = accountOptions.LockoutNewUser;
                options.User.RequireUniqueEmail = accountOptions.UniqueEmail;
                options.Lockout.MaxFailedAccessAttempts = accountOptions.LockoutMaxFailedAttempts;
                options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(accountOptions.LockoutMinutes);
            })
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();
            return services;
        }

        /// <summary>
        /// 添加JWT认证服务
        /// </summary>
        /// <param name="services"></param>
        /// <param name="jwtOptions"></param>
        /// <returns></returns>
        public static IServiceCollection AddJwtAuthentication(this IServiceCollection services, Func<JwtOptions> jwtConfig = null)
        {
            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(options =>
            {
                _jwtOptions = jwtConfig?.Invoke() ?? new JwtOptions();

                options.RequireHttpsMetadata = false;
                options.SaveToken = true;
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = true,
                    ValidateAudience = false,
                    ValidateLifetime = true,
                    ValidateIssuerSigningKey = true,
                    ValidIssuer = _jwtOptions.Issuer,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtOptions.Key)),
                    ClockSkew = TimeSpan.FromSeconds(_jwtOptions.ExpireSeconds)
                };
            });
            return services;
        }

        /// <summary>
        /// 获取jwt token
        /// </summary>
        /// <param name="claims"></param>
        /// <returns></returns>
        public static string GetJwtAuthenticationToken(this IList<Claim> claims, out DateTime expiresTime)
        {
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtOptions.Key));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            expiresTime = DateTime.Now.AddSeconds(_jwtOptions.ExpireSeconds);
            var token = new JwtSecurityToken(
               issuer: _jwtOptions.Issuer,
               claims: claims,
               expires: expiresTime,
               signingCredentials: creds);
            return new JwtSecurityTokenHandler().WriteToken(token);
        }

        /// <summary>
        /// 添加策略授权服务
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddPolicyAuthorization(this IServiceCollection services)
        {
            //策略结合声明授权
            services.AddScoped<IAuthorizationHandler, Handlers.AuthorizationHandlers.RolePermissionsHandler>();

            services.AddAuthorization(options =>
            {
                options.AddPolicy("RolePermissionsPolicy", policy => policy.AddRequirements(new Handlers.AuthorizationHandlers.RolePermissionsRequirement()));
                options.DefaultPolicy = options.GetPolicy("RolePermissionsPolicy");
            });
            return services;
        }


    }
}
